﻿using System;
using System.Collections;
using System.Web;

namespace Direct.Context
{
    [System.Diagnostics.DebuggerStepThrough]
    class ContextDataService : IContextDataService
    {
        // Contexto de thread, usado em aplicações multi-thread ou single-thread que não estejam num
        // contexto Http.
        [ThreadStatic]
        private static Hashtable _threadContextItems;

        private const string CONTEXT_HTTP_SLOT_NAME = "___http_context_data_slot___";

        private const string SYNC_OBJECT_SLOT_ID = "___ctx_sync_obj___";

        private Hashtable InternalContext
        {
            get
            {
                if (HttpContext.Current == null)
                    return (_threadContextItems = _threadContextItems ?? new Hashtable());
                else
                {
                    var result = (Hashtable)HttpContext.Current.Items[CONTEXT_HTTP_SLOT_NAME];
                    if (result == null)
                        HttpContext.Current.Items[CONTEXT_HTTP_SLOT_NAME] = result = new Hashtable();
                    return result;
                }
            }
        }


        public Object Get(String key)
        {
            return InternalContext[key];
        }

        public void Set(String key, Object value)
        {
            InternalContext[key] = value;
        }

        public bool Exists(String key)
        {
            return InternalContext.ContainsKey(key);
        }

        public int Count { get { return InternalContext.Count; } }

        public void Remove(String key)
        {
            InternalContext.Remove(key);
        }

        public object this[String key]
        {
            get { return Get(key); }
            set { Set(key, value); }
        }

        public void Clear()
        {
            InternalContext.Clear();
        }

        public Object SyncObj
        {
            get
            {
                var result = Get(SYNC_OBJECT_SLOT_ID);
                if (result == null)
                {
                    lock (this)
                    {
                        result = Get(SYNC_OBJECT_SLOT_ID);
                        if (result == null)
                        {
                            result = new Object();
                            Set(SYNC_OBJECT_SLOT_ID, result);
                        }
                    }
                }
                return result;
            }
        }
    }
}
